﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MainEntities
{
    public class User
    {
        private int _userID; // идентификатор пользователя
        public int UserID // передача идентификатора пользователя
        {
            get{return _userID;}

            set
            {
                if (value != _userID)
                    _userID = value;
            }
        }

        public static List<UserRelation> tempUserTree = new List<UserRelation>();

        string name; // имя
        string surname; //фамилия
        string fathername; // отчество
        string post; //должность
        string labilities; // обязательства
        string phone; //телефон
        string mphone; // мобилка
        string corporativeEmail; // Рабочая почта
        string personalEmail; //Домашняя почта
        string login;
        private string password;
        bool actstatus; // true - актив/false - неактив
        UserRoles userRoles; // Роли пользователя

        // публичные поля
        public string Name 
        {
            get { return name; }

            set
            {
                if (value != name)
                    name = value;
            }
        }
        public string Surname 
        {
            get { return surname; }

            set
            {
                if (value != surname)
                    surname = value;
            }
        }
        public string Fathername 
        {
            get { return fathername; }

            set
            {
                if (value != fathername)
                    fathername = value;
            }
        }
        public string Post 
        {
            get { return post; }

            set
            {
                if (value != post)
                    post = value;
            }
        }
        public string Labilities
        {
            get { return labilities; }

            set
            {
                if (value != labilities)
                    labilities = value;
            }
        }
        public string Phone
        {
            get { return phone; }

            set
            {
                if (value != phone)
                    phone = value;
            }
        }
        public string Mphone
        {
            get { return mphone; }

            set
            {
                if (value != mphone)
                    mphone = value;
            }
        }
        public string CorporativeEmail
        {
            get { return corporativeEmail; }

            set
            {
                if (value != corporativeEmail)
                    corporativeEmail = value;
            }
        }
        public string PersonalEmail
        {
            get { return personalEmail; }

            set
            {
                if (value != personalEmail)
                    personalEmail = value;
            }
        }
        public string Login
        {
            get { return login; }

            set
            {
                if (value != login)
                    login = value;
            }
        }
        public string Password
        {
            get { return password; }

            set
            {
                if (value != password)
                    password = value;
            }
        }
        public bool ActStatus
        {
            get { return actstatus; }

            set
            {
                if (value != actstatus)
                    actstatus = value;
            }
        }
        public UserRoles Roles
        {
            get { return userRoles; }

            set
            {
                if (value != userRoles)
                    userRoles = value;
            }
        }

        //пустой конструктор
        public User() { }

        // полный конструктор - с UserID, когда выгружаем информацию из БД
        public User(int _userID, string _name, string _surname, string _fathername, string _post, string _labilities,
                    string _phone, string _mphone, string с_email, string p_email, string _login, string _password,
                    bool _actstatus, UserRoles _userRoles)
        {
            UserID = _userID;
            name = _name;
            surname = _surname;
            fathername = _fathername;
            post = _post;
            labilities = _labilities;
            phone = _phone;
            mphone = _mphone;
            corporativeEmail = с_email;
            personalEmail = p_email;
            login = _login;
            password = _password;
            actstatus = _actstatus;

            userRoles = _userRoles;
        }

        // типовой конструктор - без UserID -  он нам неизвестен
        public User(string _name, string _surname, string _fathername, string _post, string _labilities,
                string _phone, string _mphone, string с_email, string p_email, string _login, UserRoles _userRoles)
        {
            name = _name;
            surname = _surname;
            fathername = _fathername;
            post = _post;
            labilities = _labilities;
            phone = _phone;
            mphone = _mphone;
            corporativeEmail = с_email;
            personalEmail = p_email;
            login = _login;
            password = generatePassword();
            actstatus = true;

            userRoles = _userRoles;

            sendLogPass();
        }

        ~User() { }

        private string generatePassword() // заглушка генератора пароля (принцип генерации нуждается в разработке)
        { return "12345"; }

        private void sendLogPass() // заглушка. будет отсылать логин/пароль на мыло когда начнём прогать сетевую часть (возможно этот метод здесь и не нужен и будет написан в интерфейсной части)
        { }

        public static User getUserFromDB(int _UserId) //получает данные юзера из БД по его ID. Без взаимодействия с БД не сделать.
        {
            User gUser = new User();
            // далее идёт извлечение и формирование полей на основе данных из БД
            return gUser;
        }

        // Метод стал ненужным

        //public static int getAvailableUserID() // упрощенный генератор идентификаторов юзера
        //{
        //    return ++lastUserID;
        //}

        public static void addUserToDB(User newUser) // добавление юзера в БД. без взаимодействия с БД не сделать
        {
        }

        public static void changeUserInDB(User changeUser) // изменение юзера в БД (присваивание параметров передаваемого юзеру в БД с тем же ИДом). без взаимодействия с БД не сделать
        {
        }

        public static void removeUserFromDB(int _UserID) // удаление юзера из БД. без взаимодейств с БД не сделать.
        {
        }

        public static void saveTreeToDB() // сохраняет текущую структуру связей в БД
        {
        }

        public static void updateTreeFromDB()  // обновляет дерево на основе БД
        {
        }


        // аутентификация пользователя. Возвращает объект типа User.
        // Если логин и пароль верны и юзер активен, возвращает соответствующего юзера (с ИД > 0), по нему можно узнать всю инфу и роли
        // Если нет такого логина, возвращает пустого юзера с UserID = -1
        // Если юзер есть, но пароль неверен, возвращает пустого юзера с UserID = -2
        // Если юзер есть и пароль верен, но юзер деактивирован, возвращает пустого юзера с UserID = -3
        // Дальнейшие действия в зависимости от результата выполняются в функции кнопки ОК окна интерфейса

        public static User authenticateUser(string _login, string _password)
        {
            updateTreeFromDB();
            bool userFound = false;
            User usr = new User();
            User tempUser = new User();
            foreach (UserRelation usRel in tempUserTree)
            {
                tempUser = getUserFromDB(usRel.UserID);
                if (tempUser.login == _login)
                {
                    userFound = true;
                    if (tempUser.password == _password)
                    {
                        if (tempUser.actstatus) usr = tempUser;
                        else usr.UserID = -3;
                    }
                    else usr.UserID = -2;
                }
            }
            if (!userFound) usr.UserID = -1;
            return usr;
        }

        //  восстановление пароля доступа. Генерирует новый пароль и возвращает true если юзер с указанным логином существует , иначе false
        public static bool restorePassword(string _login)
        {
            updateTreeFromDB();
            bool userFound = false;
            User tempUser = new User();
            foreach (UserRelation usRel in tempUserTree)
            {
                tempUser = getUserFromDB(usRel.UserID);
                if (tempUser.login == _login)
                {
                    userFound = true;
                    tempUser.generatePassword();
                    changeUserInDB(tempUser);
                    tempUser.sendLogPass();
                }
            }
            return userFound;
        }

        // функция выхода из системы целиком делается с помощью интерфейса, т.к. ничего передавать и получать не надо.

        public static bool checkLogin(String log, int _userID) // проверяет логин на уникальность, возвращает true если уникален (нет такого же у юзера с другим ID). этот метод нужно вызывать в контексте кнопки ОК. Если проверка пройдена - сохранять, а если нет - выводить предупреждение.
        {
            User tempUser = new User();
            foreach (UserRelation usRel in tempUserTree)
            {
                tempUser = getUserFromDB(usRel.UserID);
                if ((tempUser.login == log) && (tempUser.UserID != _userID)) return false;
            }
            return true;
        }

        // проверка пароля на валидность. пока пустая, нужно придумать критерии для паролей
        // вызывается из интерфейса перед собственно сменой паролей. Смена паролей вызывается если проверка пройдена
        static bool checkPassword(string _password)
        { return true; }

        // Установка нового пароля.. Возвращает false если старый пароль не верен, иначе меняет на новый и возвращает true
        public static bool setNewPassword(int _userID, String oldpassword, String newpassword) // меняет пароль на новый
        {
            User usr = getUserFromDB(_userID);
            if (usr.password == oldpassword)
            {
                usr.password = newpassword;
                changeUserInDB(usr);
                return true;
            }
            else { return false; }
        }

        public static void deactivateUser(int _UserID) // делают юзера неактивным
        {
            User usr = getUserFromDB(_UserID);
            usr.actstatus = false;
            changeUserInDB(usr);
            applyRelationChanges();
        }

        public void activateUser(int _UserID) // делает юзера активным
        {
            User usr = getUserFromDB(_UserID);
            usr.actstatus = true;
            changeUserInDB(usr);
            applyRelationChanges();
        }

        public static void addSuborder(int headID, int subID) // добавляет подчинённого в список подчинённых начальника во временное дерево. 1 парам - ид начальника
        {
            foreach (UserRelation headUs in tempUserTree) if ((headUs.UserID == headID) && (!(headUs.subordersID.Contains(subID)))) headUs.subordersID.Add(subID);
        }

        public static void removeSuborder(int ID) // удаляет подчинённого из списка подчинённых во временном дереве
        {
            foreach (UserRelation sub in tempUserTree) if (sub.subordersID.Contains(ID)) sub.subordersID.Remove(ID);
        }

        public static void addSubordersList() // обновляет список подчинённых на основе начальников по всему временному дереву
        {
            foreach (UserRelation sub in tempUserTree) if (sub.headUserID != 0) addSuborder(sub.headUserID, sub.UserID);
        }

        public static void addNewUser() // добавляем нового пользователя если всё ОК
        {

            // закоментированные строки надо поместить в интерфейс при инициализации окна, т.к. чтоб рисовать
            // связи надо создать объект UserRelation

            //UserRelation nURelation = new UserRelation();
            // tempUserTree.Add(nURelation);

            string _name = "";
            string _surname = "";
            string _fathername = "";
            string _post = "";
            string _labilities = "";
            string _phone = "";
            string _mphone = "";
            string _email = "";
            string _email2 = "";
            string _login = "";

            UserRoles roles = new UserRoles { IsAdmin = false, IsSupervisor = true, IsWorker = true };
            //bool _isadmin = false;
            //bool _issuper = false;
            // здесь должны присваиваться значения строк из интерфейса. возможно часть этого метода надо встроить в сам интерфейс а названия строк заменить на те что там используются
            User nUser = new User(_name, _surname, _fathername, _post, _labilities, _phone, _mphone, _email, _email2, _login, roles);
            foreach (UserRelation usRel in tempUserTree) if (usRel.UserID == -1) usRel.UserID = nUser.UserID;
            addUserToDB(nUser);
            applyRelationChanges();
        }

        public static void editUser(User usr) // метод сохраняет внесённые изменения в профиль пользователя. Срабатывает при подтверждении сохранения редактирования
        {
            string _name = "";
            string _surname = "";
            string _fathername = "";
            string _post = "";
            string _labilities = "";
            string _phone = "";
            string _mphone = "";
            string c_email = "";
            string p_email = "";
            string _login = "";

            UserRoles roles = new UserRoles { IsAdmin = false, IsSupervisor = true, IsWorker = true };
            //bool _isadmin = false;
            //bool _issuper = false;

            // здесь должны присваиваться значения строк из интерфейса. Получение и вызов функции из БД будет в теле функции интерфейса
            usr.name = _name;
            usr.surname = _surname;
            usr.fathername = _fathername;
            usr.post = _post;
            usr.labilities = _labilities;
            usr.phone = _phone;
            usr.mphone = _mphone;
            usr.corporativeEmail = c_email;
            usr.personalEmail = p_email;
            usr.login = _login;
            usr.userRoles = roles;
            changeUserInDB(usr);
            applyRelationChanges();
        }

        public static void removeUser(int _userID) // удаляет юзера из временного дерева. Срабатывает при подтверждении удаления.
        {
            foreach (UserRelation usr in tempUserTree)
                if (usr.headUserID == _userID) usr.removeHead(_userID);
            removeUserFromDB(_userID);
            applyRelationChanges();
        }

        public static void applyRelationChanges() // применяет изменения в иерарх. структуре основного дерева на основе временного.
        {
            //userTree = new List<UserRelation>();
            //foreach (UserRelation usRel in tempUserTree) userTree.Add(usRel);

            //В этом методе будешь сразу работать с tempUserTree, не с userTree!
            saveTreeToDB();
        }

        public static void cancelRelationChanges() // откатывает изменения в структуре дерева. Будет применяться при нажатии отмены в интерфейсе
        {
            tempUserTree.Clear();

            //Пригодится такой метод:
            //public void loadUserTreeFromDB();


            //+ предусмотри для него перегрузки, например public void loadUserTreeFromDB(int userIerarchyLevel) {}
            // - Чтобы выгружать из БД не все дерево пользователей, а только нужное нам подмножество ветвей этого дерева.
            // (В ответ на замечания подгруппы "Мафия" про чрезмерную нагрузку на сервер и на клиента при
            // заполненении дерева tempUserTree каждым пользователем системы. Я согласен, это избыточно.

            //foreach (UserRelation usRel in userTree) tempUserTree.Add(usRel);
        }

        public void loadUserTreeFromDB() { }

        public void loadUserTreeFromDB(int userIerarchyLevel) { }


        public static void sendReport(int _taskID, string report) { } // будет отправлять отчет супервайзеру. просмотр реализуется через интерфейс. где хранить отчет хз (возможно через почту)

        //public Task getTask(int ID) { }

    }


    public class UserRelation // элемент иерархического дерева
    {
        private int _userID; // идентификатор пользователя
        public int UserID // передача идентификатора пользователя
        {
            get
            {
                return _userID;
            }

            set
            {
                if (value != _userID)
                    _userID = value;
            }
        }
        public int headUserID; // идентификатор начальника
        public List<int> subordersID; // идентификаторы подчинённых
        public List<int> userTasksID; // идентификаторы задач пользователя

        public UserRelation()
        {
            UserID = -1; // временный идентификатор нового не созданного юзера
            headUserID = 0;
        }
        public UserRelation(int ID)
        {
            UserID = ID;
            headUserID = 0;
        }
        ~UserRelation() { User.tempUserTree.Remove(this); }
        public void changeHead(int hID) // меняет начальника
        {
            if (headUserID != 0) User.removeSuborder(UserID);
            headUserID = hID;
            User.addSuborder(headUserID, UserID);
        }
        public void removeHead(int hID) // меняет подчиненного
        {
            User.removeSuborder(UserID);
            headUserID = 0;
        }
        public void addTask(int taskID) // добавляет задачу
        {
            userTasksID.Add(taskID);
        }
        public void removeTask(int taskID) // удаляет задачу
        {
            if (userTasksID.Contains(taskID))
            {
                userTasksID.Remove(taskID);
                // надо добавить получение задачи по ID и присвоение ей статуса notAssigned
            }
        }
        public static UserRelation getUserRelation(int _UserID) // получает связь по идентификатору
        {
            foreach (UserRelation usRel in User.tempUserTree) if (usRel.UserID == _UserID) return usRel;
            return null;
        }
        public int level() // уровень иерархии
        {
            if (headUserID == 0) return 0;
            else return getUserRelation(headUserID).level();
        }
    }

    public class UserRoles
    {
        private bool _IsAdmin;        //статус админа
        private bool _IsSupervisor;   // статус супервайзора
        private bool _IsWorker;       // статус работника

        public bool IsAdmin { get; set; }
        public bool IsSupervisor { get; set; }
        public bool IsWorker { get; set; }

        public UserRoles(bool a, bool s, bool w)
        {
            _IsAdmin = a;
            _IsSupervisor = s;
            _IsWorker = w;
        }

        public UserRoles() { }

    }

}